use crate::println;
use core::arch::asm;

// 描述符表指针结构 (用于 lidt 指令)
#[repr(C, packed)]
pub struct DescriptorTablePointer {
    limit: u16,
    base: u64,
}

// 中断栈帧结构
#[repr(C)]
pub struct InterruptStackFrame {
    instruction_pointer: u64,
    code_segment: u64,
    cpu_flags: u64,
    stack_pointer: u64,
    stack_segment: u64,
}

// 中断描述符表项
#[repr(C, packed)]
#[derive(Debug, Clone, Copy)]
pub struct IdtEntry {
    pub offset_low: u16,  // 处理程序地址的低16位
    pub selector: u16,    // 代码段选择子
    pub ist: u8,          // 中断栈表索引
    pub type_attr: u8,    // 类型和属性
    pub offset_mid: u16,  // 处理程序地址的中间16位
    pub offset_high: u32, // 处理程序地址的高32位
    pub zero: u32,        // 保留
}

// 全局 IDT
static mut IDT: [IdtEntry; 256] = [IdtEntry {
    offset_low: 0,
    selector: 0,
    ist: 0,
    type_attr: 0,
    offset_mid: 0,
    offset_high: 0,
    zero: 0,
}; 256];

// 设置单个 IDT 条目
pub fn set_idt_entry(index: usize, handler_addr: u64, selector: u16, flags: u8) {
    unsafe {
        IDT[index] = IdtEntry {
            offset_low: handler_addr as u16,
            offset_mid: (handler_addr >> 16) as u16,
            offset_high: (handler_addr >> 32) as u32,
            selector,
            ist: 0,
            type_attr: flags,
            zero: 0,
        };
    }
}

// 初始化并加载 IDT
fn init_idt() {
    // 设置双重错误处理程序 (索引8)
    set_idt_entry(8, double_fault_handler as *const () as u64, 0x08, 0x8E);
    let idt_pointer = DescriptorTablePointer {
        limit: (unsafe { core::mem::size_of_val(&IDT) } - 1) as u16,
        base: &raw const IDT as *const _ as u64,
    };

    // 加载 IDT
    unsafe {
        asm!("lidt [{}]", in(reg) &idt_pointer, options(nostack, readonly));
    }

    // 启用中断
    unsafe {
        asm!("sti");
    }
}

// 处理双重错误的中断处理函数
#[no_mangle]
pub extern "x86-interrupt" fn double_fault_handler(
    _stack_frame: &mut InterruptStackFrame,
    _error_code: u64,
) {
    // 处理双重错误
    unsafe {
        asm!(
            "push rax",
            "mov rax, {print_func}",
            "call rax",
            "pop rax",
            "iretq",
            print_func = sym double_fault_print,
            options(noreturn)
        );
    }
    println!("!!! DOUBLE FAULT !!!");
    loop {}
}
// 双重错误打印函数
fn double_fault_print() {
    println!("!!! DOUBLE FAULT !!!");
}

pub fn init() {
    init_idt();
    // 在这里添加实际的中断描述符表设置
}
